#import <SpringBoard/SBApplication.h>
#import <SpringBoard/SBApplicationController.h>
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import <LockInfo/Plugin.h>

#import "FWCommon.h"
#import "FWListView.h"
#import "FWDotView.h"
#import "FWApplication.h"
#import "FWIconDotView.h"
#import "FWRoundedLabel.h"


CGFloat const kFWListViewDotSize = 9;
CGFloat const kFWListViewMarkerSpace = 18;
CGFloat const kFWListViewMarkerSize = 16;
CGFloat const kFWListViewDetailMargin = 22;
CGFloat const kFWListViewSeparatorSize = 2;
CGFloat const kFWListViewMarkerInset = 0;

NSInteger const kFWListViewBorderInset = 4;


@implementation FWListView

@synthesize dot, headerText, headerBackground, summaryText, detailText, detailTextAlternate, highlightText, flags, singleLine, expandSingleLine, largestIcon, leftReservedSpace, drawBorder, abbreviateDetail;


// ******************************************************************************************
#pragma mark -
#pragma mark Initialisation and object management

- (id)initWithFrame:(CGRect)frame table:(LITableView *)table
{
    if (self = [super initWithFrame:frame]) {
        self.largestIcon = kFWListViewMarkerSize;
        self.leftReservedSpace = 0;
        
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        self.contentMode = UIViewContentModeRedraw;
        self.autoresizesSubviews = YES;
        self.backgroundColor = [UIColor clearColor];
        
        self.dot = [[[FWDotView alloc] initWithFrame:CGRectMake(4, 0, kFWListViewDotSize, kFWListViewDotSize)] autorelease];
        self.dot.backgroundColor = [UIColor clearColor];

        self.summaryText = [table labelWithFrame:CGRectZero];
        self.summaryText.frame = CGRectZero;
        self.summaryText.autoresizingMask = UIViewAutoresizingNone;
        self.summaryText.backgroundColor = [UIColor clearColor];
        
        self.detailText = [table labelWithFrame:CGRectZero];
        self.detailText.frame = CGRectZero;
        self.detailText.autoresizingMask = UIViewAutoresizingNone;
        self.detailText.backgroundColor = [UIColor clearColor];
        
        self.highlightText =  [[[FWRoundedLabel alloc] initWithFrame:CGRectZero] autorelease];
        
        [self addSubview:self.dot];
        [self addSubview:self.summaryText];
        [self addSubview:self.detailText];
        [self addSubview:self.highlightText];
    }
    
    return self;
}

-(void)dealloc
{
    [dot release];
    [headerText release];
    [headerBackground release];
    [summaryText release];
    [detailText release];
    [detailTextAlternate release];
    [highlightText release];
    [flags release];
    
    [super dealloc];
}

- (void)addHeader:(LITableView*)table
{
    if (!self.headerBackground) {
        self.headerText = [table labelWithFrame:CGRectZero];
        self.headerText.style = table.theme.summaryStyle;
        //    self.headerText.frame = CGRectZero;
        self.headerText.autoresizingMask = UIViewAutoresizingNone;
        self.headerText.backgroundColor = [UIColor clearColor];
        
        self.headerBackground = [[[UIImageView alloc] initWithFrame:CGRectZero] autorelease];
        [self.headerBackground addSubview:self.headerText];
        self.headerBackground.image = [[table sectionSubheader] stretchableImageWithLeftCapWidth:0
                                                                                    topCapHeight:0];
        
        [self addSubview:self.headerBackground];
    }
}

- (void)removeHeader
{
    if (self.headerBackground) {
        [self.headerBackground removeFromSuperview];
        
        self.headerText = nil;
        self.headerBackground = nil;
    }
}

// ******************************************************************************************
#pragma mark -
#pragma mark Row height support

+ (CGFloat)heightOfSummaryRowWithFont:(UIFont*)font withHeader:(BOOL)header withFollowingRow:(BOOL)following
{
    CGFloat height = font.leading;
    
    if (!following)
        ++height;
    
    if (header)
        height += font.leading;
    
    return height;
}

+ (CGFloat)heightOfDetailRowWithFont:(UIFont*)font
{
    CGFloat height = font.leading;
    return height;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Layout support

- (void)layoutSummaryRow:(CGRect)rect
{
    CGFloat rightMargin = rect.size.width - kFWListViewSeparatorSize;

    // Get the space we will be using for markers
    CGFloat flagHeight = rect.size.height;
    if (flagHeight < kFWListViewMarkerSpace)
        flagHeight = kFWListViewMarkerSpace;
    
    for (UIView* flag in self.flags) {
        if (!flag.isHidden) {
            // Put action half way up the name line unless it is too small
            CGRect flagRect = flag.frame;
            CGFloat pos = (flagHeight - flagRect.size.height) / 2;
            if (pos < 0)
                pos = 0;

            flagRect = CGRectMake(rect.origin.x + rightMargin - flagRect.size.width,
                                  rect.origin.y + pos,
                                  flagRect.size.width,
                                  flagRect.size.height);
            
            rightMargin = rightMargin - flagRect.size.width - kFWListViewSeparatorSize;
            flag.frame = flagRect;
            
            if (flagRect.size.width == kFWListViewMarkerSpace)
                rightMargin -= kFWListViewSeparatorSize;
        }
    }
    
    CGRect summaryRect = CGRectMake(rect.origin.x + kFWListViewDetailMargin + leftReservedSpace,
                                    rect.origin.y,
                                    rightMargin - kFWListViewDetailMargin - leftReservedSpace,
                                    rect.size.height);
    self.summaryText.frame = summaryRect;
    
    // LILabel seems to stretch its text on rotation unless we do this
    [self.summaryText setNeedsDisplay];
}

- (void)layoutDetailRow:(CGRect)rect
{
    CGFloat leftMargin = rect.origin.x;
    CGFloat rightMargin = rect.origin.x + rect.size.width - kFWListViewSeparatorSize;

    // If we have a highlight string then try to allow that as much room as it needs
    if (!self.highlightText.isHidden) {
        CGFloat priorityWidth = [self.highlightText sizeForHeight:rect.size.height].width;
        CGFloat dueWidth = self.detailText.hidden ? 0 : [self.detailText.text sizeWithFont:self.detailText.style.font].width;
        
        // Is the line too long?
        if (!self.detailText.isHidden) {
            if ((leftMargin + priorityWidth + kFWListViewSeparatorSize + dueWidth) > rightMargin) {
                if (self.detailTextAlternate) {
                    CGFloat shortWidth = [self.detailTextAlternate sizeWithFont:self.detailText.style.font].width;
                    if (shortWidth < dueWidth) {
                        self.detailText.text = self.detailTextAlternate;
                        dueWidth = shortWidth;
                    }
                }				
                
                if ((leftMargin + priorityWidth + kFWListViewSeparatorSize + dueWidth) > rightMargin) {
                    CGFloat reqPriorityWidth = rightMargin - leftMargin - kFWListViewSeparatorSize - dueWidth;
                    if (abbreviateDetail && (reqPriorityWidth < priorityWidth)) {
                        dueWidth -= priorityWidth - reqPriorityWidth;
                        reqPriorityWidth = priorityWidth;
                    }
                    
                    priorityWidth = reqPriorityWidth;
                }
            }
        }
        
        CGRect highlightRect = CGRectMake(leftMargin, rect.origin.y, priorityWidth, rect.size.height);
        leftMargin += highlightRect.size.width + kFWListViewSeparatorSize;
        self.highlightText.frame = highlightRect;
        
        // LILabel seems to stretch its text on rotation unless we do this
        [self.highlightText setNeedsDisplay];
    }
    
    CGRect detailRect = CGRectMake(leftMargin, rect.origin.y, rightMargin - leftMargin, rect.size.height);
    self.detailText.frame = detailRect;
        
    if (!self.detailText.isHidden) {
        // LILabel seems to stretch its text on rotation unless we do this
        [self.detailText setNeedsDisplay];
    }
    
    // Redraw ourselves
    [self setNeedsDisplay];
}

- (void)layoutSubviews
{
#ifdef DEVELOPMENT_MODE
    self.detailText.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3];
    self.summaryText.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3];
#endif
    
    CGFloat summaryHeight = [[self class] heightOfSummaryRowWithFont:self.summaryText.style.font
                                                          withHeader:NO
                                                    withFollowingRow:!singleLine];
    CGFloat detailHeight = [[self class] heightOfDetailRowWithFont:self.detailText.style.font];
    CGFloat headerHeight = self.summaryText.style.font.leading;
    
    if (summaryHeight < 2)
        return;
    
    CGRect rect = self.superview.bounds;
    self.frame = CGRectMake(0, 0, rect.size.width, rect.size.height);

    CGRect detailRect, summaryRect, headerRect;
    NSInteger inset = drawBorder ? kFWListViewBorderInset : 0;
    
    // Size of the header if there is one
    headerRect = self.headerBackground ? CGRectMake(0, 0, rect.size.width, headerHeight) : CGRectZero;
    
    if (singleLine) {
        CGFloat offset = (summaryHeight - detailHeight) / 2;
        CGFloat width = rect.size.width * 0.6;

        if (expandSingleLine && self.detailText.hidden)
            width = rect.size.width;
        
        summaryRect = CGRectMake(0, headerRect.size.height + inset, width, summaryHeight);
        detailRect = CGRectMake(width + kFWListViewSeparatorSize * 2, 
                                offset + headerRect.size.height + inset,
                                rect.size.width - width - inset - leftReservedSpace - kFWListViewSeparatorSize * 2,
                                detailHeight);
    }
    else {
        summaryRect = CGRectMake(0, headerRect.size.height + inset, rect.size.width - inset, summaryHeight);
        detailRect = CGRectMake(kFWListViewDetailMargin + leftReservedSpace,
                                summaryHeight + headerRect.size.height + inset,
                                rect.size.width - leftReservedSpace - kFWListViewDetailMargin - inset,
                                detailHeight);
    }
    
    if (self.headerBackground) {
        self.headerBackground.frame = headerRect;
        
        if (!self.dot.isHidden) {
            headerRect.origin.x += self.dot.frame.origin.x;
            headerRect.size.width -= headerRect.origin.x;
        }
        
        self.headerText.frame = headerRect;

        // LILabel seems to stretch its text on rotation unless we do this
        [self.headerText setNeedsDisplay];
    }
    
    if (!self.detailText.isHidden || !self.highlightText.isHidden)
        [self layoutDetailRow:detailRect];
    
    [self layoutSummaryRow:summaryRect];

    if (!self.dot.hidden) {
        // Place the dot half way up the title line
        CGRect dotRect = self.dot.frame;
        CGFloat fieldHeight = singleLine || (self.detailText.isHidden && self.highlightText.isHidden) ? fmax(summaryRect.size.height, detailRect.size.height) : (summaryRect.size.height + detailRect.size.height);
        CGFloat pos = (fieldHeight - dotRect.size.height) / 2;
        if (pos < 0)
            pos = 0;
        
        self.dot.frame = CGRectMake(summaryRect.origin.x + dotRect.origin.x,
                                    summaryRect.origin.y + pos,
                                    dotRect.size.width,
                                    dotRect.size.height);
    }
}


- (void)drawRect:(CGRect)rect
{
    if (!drawBorder)
        return;
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);

    CGContextBeginPath(context);
    
    CGContextSetLineWidth(context, 2);
    CGContextSetStrokeColorWithColor(context, [self.summaryText.style.textColor colorWithAlphaComponent:0.75].CGColor);

    rect = self.frame;
    if (headerBackground) {
        rect.origin.y += headerBackground.frame.size.height;
        rect.size.height -= headerBackground.frame.size.height;
    }
    
    rect = CGRectInset(rect, 1, kFWListViewBorderInset / 2);
    
    CGFloat dashArray[] = {6, 3};
    CGContextSetLineDash(context, 0, dashArray, sizeof(dashArray) / sizeof(CGFloat));
    
    CGFloat segRadius = 6;
    
    CGFloat minx = CGRectGetMinX(rect);
    CGFloat midx = CGRectGetMidX(rect);
    CGFloat maxx = CGRectGetMaxX(rect);
    CGFloat miny = CGRectGetMinY(rect);
    CGFloat midy = CGRectGetMidY(rect);
    CGFloat maxy = CGRectGetMaxY(rect);
    
    CGContextMoveToPoint(context, minx, midy);
    CGContextAddArcToPoint(context, minx, miny, midx, miny, segRadius);
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, segRadius);
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, segRadius);
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, segRadius);
    CGContextClosePath(context);
    
    CGContextDrawPath(context, kCGPathStroke);
    
    CGContextRestoreGState(context);
}

@end
